/*
* Copyright (c) 2011 Connection Road.  All rights reserved.
* This program and the accompanying material are made available
* under the terms of the Eclipse Public Licnese v1.0 which is
* available at http://www.eclipse.org/legal/epl-v10.html
*/

using System;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using CrSyncFilesForms.Properties;
using CrSyncFilesForms.Utils;
using CrSyncFilesUtils;
using Microsoft.Win32;

namespace CrSyncFilesForms
{
    public partial class Main : Form
    {
        public CrSyncUiLogViewer DialogSyncToyLogs;
        public CrSyncUiFolderPairWizard DialogFolderPairWizard;
        public CrSyncUiRun DialogSyncToyResult;
        public CrSyncFilesUiMainView CurrentView;

        private CrSyncUiPreLoaderDialog _preloaderCreateNewFolder;
        private CrSyncUiPreLoaderDialog _preLoaderDeleteFolderPair;
        private CrSyncUiPreLoaderDialog _preLoaderImport;
        private CrSyncUiPreLoaderDialog _preLoaderExport;
        private FileSyncPairInfo _newFolderPair;

        private MenuItem MenuItemCreateNewFolderPair { get; set; }
        private MenuItem MenuItemDeleteFolderPair { get; set; }
        private MenuItem MenuItemRenameFolderPair { get; set; }
        private MenuItem MenuItemScheduleFolderPair { get; set; }
        private TreeNode _currentPairNode;
        
        private Brush _brushBlack;
        private Brush _brushWhite;
        private IntPtr _mainWindowHandle;

        private bool _resetOnGoing;
        private bool _doneLoadingFromLastKnownFolderPair; // Flag to let the FolderPairTreeView knows that loading folder pair name from last known pair is done.
        
        
        private const string KAll_FOLDER_PAIRS = "All Folder Pairs";
        private const string KCURRENT_FOLDER_PAIR = "CURRENT_FOLDER_PAIR";
        
        private const string KRESULT = "RESULT";
        
        private const string KERROR = "ERROR";
        private const string KMESSAGE = "MESSAGE";
        private const string KHAS_MIRROR = "HAS_MIRROR";
        
        private readonly Color _unfocusedFolderPairColor = CRSyncColors.ListViewBackColor;

        

        public Main()
        {
            BeforeInitializeExtension();

            InitializeComponent();
            
            Shown += CallBackShown;
            ButtonPreview.Click += CallBackPreview;
            ButtonRun.Click += CallBackRun;

            InitializeExtension();
        }

        // Provides a way to initialize other class implementation
        // without attaching them on to this class.
        partial void BeforeInitializeExtension();
        partial void InitializeExtension(); 
        partial void OnLoadExtension();
        partial void OnShownExtension();
        partial void OnShowAdvancedOptionsExtension();

        private void CallBackLoad(object sender, EventArgs e)
        {
            // ---- COLOR SCHEME ----
            BackColor = CRSyncColors.MainWindowBackGround;
            FolderPairTree.BackColor = CRSyncColors.MainWindowBackGround;
            FolderPairTree.ForeColor = CRSyncColors.ListViewForeColor;

            MinimumSize = new Size(860, 600);

            Icon = Resources.CRSyncFilesWIconCollection;

            AcceptButton = ButtonCreateNewFolderPair;

            InitializeFolderPairTreeImages();
            InitializeFolderPairTree();
            InitializeDefaultActions();

            InitializeWindowPositionAndDimension();

            Closed += CallBackClosed;

            PanelWelcome.LinkCreateFolderPair.LinkClicked += CallBackCreateNewFolderPair;
            PanelWelcome.LinkHelp.LinkClicked += CallBackHelp;

            
            
            // Advance option menu items
            MenuItemAdvancedOptions.Checked = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemResetRegistryKey.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemDiagnosticsMode.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemDiagnosticPause.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemFolderPairExport.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemFolderPairImport.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemWriteToEvent.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
            MenuItemWriteToEvent.Checked = Settings.Default.CFG_WRITE_TO_EVENT_VIEWER;

            if(ApplicationGlobals.Verbose)
            {
                MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
                MenuItemDiagnosticsMode.Enabled = false;
            }
            else
            {
                MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
                MenuItemDiagnosticsMode.Enabled = true;
            }


            _mainWindowHandle = Handle;
            
            _brushBlack = Brushes.Black;
            _brushWhite = Brushes.White;
            
            Menu = MainMenuDefault;
           
            MenuItemDiagnosticPause.Checked = (ApplicationGlobals.CfgDefaultPauseTime == 0) ? false : true;
            

            //Initialize Application Name
            Text = Resources.TEXT_TITLE_NAME;
            
            MenuItemCreateNewFolderPair = new MenuItem("Create New Folder Pair...");
            MenuItemDeleteFolderPair = new MenuItem("Delete <>");
            MenuItemRenameFolderPair = new MenuItem("Rename <>");
            MenuItemScheduleFolderPair = new MenuItem("Schedule <>");

            MenuItemDeleteFolderPair.Click += CallBackDeleteFolderPair;
            MenuItemRenameFolderPair.Click += CallBackRenameFolderPair;
            MenuItemCreateNewFolderPair.Click += CallBackCreateNewFolderPair;


            FolderPairTree.ContextMenu = FolderPairsContextMenu;

            // Show the welcome page when the database is empty
            if (ApplicationGlobals.PairManager.AvailableFolderPairs().Count <= 0)
            {
                SetView(CrSyncFilesUiMainView.Default);
            }
            else
            {
                SelectDefaultFolderPair();
            }

            _doneLoadingFromLastKnownFolderPair = true;

            // Initialize stuffs in header
            CloudInfoHeader.Visible = false;

            // Give the other partial class implementation some way to initialize without having to
            // attach itself to the initialization process
            OnLoadExtension(); 

            InitializeCriticalErrorLink();
        }


        //------------------------ HELPER METHODS ------------------------------
        
        public void SetVerboseWindowAsOpenState(bool openState)
        {
            if(openState)
            {
                MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
                MenuItemDiagnosticsMode.Enabled = false;
            }
            else
            {
                MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
                MenuItemDiagnosticsMode.Enabled = true;
            }
        }

        /// <summary>
        /// Initializes the current window location and dimension from the last known coordinates and window size.
        /// </summary>
        private void InitializeWindowPositionAndDimension()
        {
            Height = ( Settings.Default.CFG_WINDOW_HEIGHT == 0 ) ? Height : Settings.Default.CFG_WINDOW_HEIGHT;
            Width = (Settings.Default.CFG_WINDOW_WIDTH == 0) ? Width : Settings.Default.CFG_WINDOW_WIDTH;

            var position = new Point(
                (Settings.Default.CFG_WINDOW_X == 0) ? Location.X : Settings.Default.CFG_WINDOW_X,
                (Settings.Default.CFG_WINDOW_Y == 0) ? Location.Y : Settings.Default.CFG_WINDOW_Y
                );
            Location = position;

            ApplicationGlobals.SetVerboseMessage("CURRENT WINDOW POSITION = " + Location.X + ", " + Location.Y);
            ApplicationGlobals.SetVerboseMessage("CURRENT WINDOW DIMENSION = H" + Height + "/W" + Width);
        }


        /// <summary>
        /// Store the window coordinates and window size
        /// </summary>
        private void StoreWindowPositionAndDimension()
        {
            ApplicationGlobals.SetVerboseMessage("STORING CURRENT WINDOW POSITION = "+Location.X+", "+Location.Y);
            ApplicationGlobals.SetVerboseMessage("STORING CURRENT WINDOW DIMENSION = H"+Height+"/W"+Width);
            Settings.Default.CFG_WINDOW_HEIGHT = Height;
            Settings.Default.CFG_WINDOW_WIDTH = Width;
            Settings.Default.CFG_WINDOW_X = Location.X;
            Settings.Default.CFG_WINDOW_Y = Location.Y;
            Settings.Default.Save();
        }



        /// <summary>
        /// Populate the image list used as schedule identifier in FoledrPairTree.  (The blue circle with a white S)
        /// Must be called before initializing FolderPaiTree TreeView object.
        /// </summary>
        protected void InitializeFolderPairTreeImages()
        {
            ImageListScheduler.Images.Add(Resources.spacer);
            ImageListScheduler.Images.Add(Resources.sOnRoundSmall);
            ImageListScheduler.Images.Add(Resources.sOnRoundSmall2);
            ImageListScheduler.Images.Add(Resources.sOnRoundSmall3);
        }

      
        /// <summary>
        /// Prepares the link to the critical errors log to be shown.
        /// </summary>
        private void InitializeCriticalErrorLink()
        {
            LinkLabelCriticalLog.Visible = bool.Parse(ApplicationGlobals.RegistryManager.GetValueForKey("CFG_SHOW_CRITICAL_LOG", "False"));
        }

        private void ShowCriticalLogViewer()
        {
            Cursor = Cursors.WaitCursor;
            var criticalLogViewer = new CrSyncUiLogViewer(ApplicationGlobals.CrSyncCriticalLogFilePath,"CRSyncFiles Critical Errors Log");
            criticalLogViewer.ShowDialog(this);
            Cursor = Cursors.Default;
        }

        private  void LaunchOnlineHelpFile()
        {
            Process.Start(Settings.Default.CFG_URL_ONLINE_DOC);
        }


        
        /// <summary>
        /// Set the default selected Folder Pair  using the last known pair when the application loads.
        /// </summary>
        private void SelectDefaultFolderPair()
        {
            // Load known last Folder Pair
            if (!string.IsNullOrEmpty(Settings.Default.CFG_LAST_FOLDER_PAIR))
            {
                LoadFolderPairNamed(Settings.Default.CFG_LAST_FOLDER_PAIR);
                foreach (var node in FolderPairTree.Nodes.Cast<TreeNode>().Where(node => node.Text == Settings.Default.CFG_LAST_FOLDER_PAIR))
                {
                    FolderPairTree.SelectedNode = node;
                    break;
                }
            }
            else
            {
                // Select the top most Folder Pair if no known last Folder Pair was selected.
                if (FolderPairTree.Nodes.Count >= 1)
                {
                    FolderPairTree.SelectedNode = FolderPairTree.Nodes[0];
                }
            }
        }


        /// <summary>
        /// Set the type of view to use in the main window.
        /// </summary>
        /// <param name="view"></param>
        public void SetView(CrSyncFilesUiMainView view)
        {
            switch(view)
            {
                case CrSyncFilesUiMainView.Default:
                    PanelWelcome.Show();
                    PanelFolderPair.Hide();
                    PanelAllFolderPairs.Hide();
                    CurrentView = view;
                    break;
                case CrSyncFilesUiMainView.Settings:
                    PanelWelcome.Hide();
                    PanelFolderPair.Show();
                    PanelAllFolderPairs.Hide();
                    CurrentView = view;
                    break;
                case CrSyncFilesUiMainView.All:
                    PanelWelcome.Hide();
                    PanelFolderPair.Hide();
                    PanelAllFolderPairs.Show();
                    CurrentView = view;
                    break;
                default:
                    PanelWelcome.Show();
                    PanelFolderPair.Hide();
                    PanelAllFolderPairs.Hide();
                    CurrentView = CrSyncFilesUiMainView.Default;
                    break;

            }
        }


        /// <summary>
        /// Ensure availability of default action, when Folder Pairs list is empty
        /// </summary>
        private void InitializeDefaultActions() {
            if (FolderPairTree.Nodes.Count >= 2)
            {
                // If Folder Pair list is empty disable export option.
                MenuItemFolderPairExport.Enabled = true;

                ButtonRenameFolderPair.Enabled = true;
                ButtonDeleteFolderPair.Enabled = true;
                ButtonCreateNewFolderPair.Enabled = true;
                ButtonPreview.Enabled = true;
                ButtonRun.Enabled = true;
                FolderPairTree.SelectedNode = FolderPairTree.Nodes[0];
                FolderPairTree.Select();
            }
            else
            {
                // If Folder Pair list is empty disable export option
                MenuItemFolderPairExport.Enabled = false;

                ButtonRenameFolderPair.Enabled = false;
                ButtonDeleteFolderPair.Enabled = false;
                ButtonCreateNewFolderPair.Enabled = true;
                ButtonPreview.Enabled = false;
                ButtonRun.Enabled = false;
                SetView(CrSyncFilesUiMainView.Default);
            }
        }


        /// <summary>
        /// Initializes and updates the list of available Folder Pairs.
        /// Attaches appropriate image for identifying scheduled Folder Pairs
        /// </summary>
        private void InitializeFolderPairTree()
        {
            try
            {
                var overrideMethodInfo = GetType().GetMethod("OverrideInitializeFolderPairTree");
                overrideMethodInfo.Invoke(this, null);
            }
            catch (NullReferenceException)
            {
                var availableFolderPairs = ApplicationGlobals.PairManager.AvailableFolderPairs();
                FolderPairTree.Nodes.Clear();
                FolderPairTree.ImageIndex = 0;

                foreach (var pairItem in availableFolderPairs)
                {
                    var treeNode = new TreeNode(pairItem.Value.FolderPairName);
                    FolderPairTree.Nodes.Add(treeNode);
                }

                if (availableFolderPairs.Count >= 10)
                {
                    var defaultNode = new TreeNode(KAll_FOLDER_PAIRS);
                    FolderPairTree.Nodes.Insert(0, defaultNode);
                }
                else if (availableFolderPairs.Count >= 1)
                {
                    var defaultNode = new TreeNode(KAll_FOLDER_PAIRS);
                    FolderPairTree.Nodes.Add(defaultNode);

                }

                MenuItemFolderPairExport.Enabled = availableFolderPairs.Count >= 1;
            }
        }


        /// <summary>
        /// Loads information about the Folder Pair.
        /// Performs a preselect on the current Folder Pair.
        /// </summary>
        /// <param name="aName">The name of the Folder Pair</param>
        public void LoadFolderPairNamed(string aName)
        {
            try
            {
                var overrideMethodInfo = GetType().GetMethod("OverrideLoadFolderPairNamed");
                var overrideArgs = new object[] {aName};
                overrideMethodInfo.Invoke(this, overrideArgs);
            }
            catch (NullReferenceException)
            {
                if (aName == KAll_FOLDER_PAIRS)
                {
                    var pairItems = ApplicationGlobals.PairManager.AvailableFolderPairs();
                    var folderPairs = pairItems.Select(pairItem => pairItem.Value).ToList();
                    SetView(CrSyncFilesUiMainView.All);
                    PanelAllFolderPairs.LoadFolderPairs(folderPairs);

                    ButtonPreview.Text = Resources.TEXT_PREVIEW_ALL;
                    ButtonRun.Text = Resources.TEXT_RUN_ALL;
                    ButtonPreview.Enabled = true;
                    ButtonRun.Enabled = true;
                    ButtonRenameFolderPair.Enabled = false;
                    ButtonDeleteFolderPair.Enabled = false;
                }
                else
                {
                    SetView(CrSyncFilesUiMainView.Settings);
                    if (ApplicationGlobals.PairManager.HasFolderPairNamed(aName))
                    {
                        var currentFolderPair = ApplicationGlobals.PairManager.CurrentFolderPair;
                        PanelFolderPair.LoadFolderPair(currentFolderPair);

                        // Add an indicator to the left panel.
                        try
                        {
                            ButtonPreview.Enabled =
                            ButtonRun.Enabled = ValidateFolderPair(ApplicationGlobals.PairManager.CurrentFolderPair);
                        }
                        catch
                        {
                            //NOTE: No item is selected yet. Suppressing possible errors.
                        }

                        // Check and disable action buttons if one of Folder Pair's location is missing.
                        if (currentFolderPair.Validate(ApplicationGlobals.PairManager) == CrSyncFileLocationResult.Valid)
                        {
                            ButtonPreview.Enabled = true;
                            ButtonRun.Enabled = true;
                        }
                        else
                        {
                            ButtonPreview.Enabled = false;
                            ButtonRun.Enabled = false;
                        }
                    }


                    ButtonPreview.Text = Resources.TEXT_PREVIEW;
                    ButtonRun.Text = Resources.TEXT_RUN;
                    ButtonRenameFolderPair.Enabled = true;
                    ButtonDeleteFolderPair.Enabled = true;

                }
            }
        }
               
       


       private bool ValidateFolderPair(FileSyncPairInfo folderPair)
       {
           //// Validate Folder Pair
           var folderPairValidity = folderPair.Validate(ApplicationGlobals.PairManager);
           if (folderPairValidity == CrSyncFileLocationResult.Valid)
           {
               return true;
           }
           ApplicationGlobals.WriteEventLog(string.Format("One or Both Folders for CRSyncFiles Folder Pair : {0} no longer exists on the Hard Drive.", folderPair.FolderPairName), EventLogEntryType.Information);
           return false;
       }


        /// <summary>
        /// Displays message box and inform user that a marker file is missing.
        /// </summary>
        /// <param name="folderPair"></param>
        /// <returns></returns>
       private bool CheckMissingEndpointAndContinue(FileSyncPairInfo folderPair)
       {
           DialogResult leftResult;
           DialogResult rightResult;
           var message = "";
           const string caption = "CRSyncFiles Folder Pair Endpoint does not exist.";
           if (File.Exists(folderPair.LeftFolder.MarkerFilePath))
           {
               leftResult = DialogResult.Yes;
           }
           else
           {
               message = "CRSyncFiles has detected that you haven't synchronized Folder Pair : " + folderPair.FolderPairName + " with the following end point " + folderPair.LeftFolder.Path + ". Would you like to continue?";
               leftResult = MessageBox.Show(message,
                               caption,
                               MessageBoxButtons.YesNo,
                               MessageBoxIcon.Question,
                               MessageBoxDefaultButton.Button2);
           }

           if (folderPair.RightFolder.LocationType == CrSyncFileLocationTypes.Azure) // NOTE: Remove from codeplex
           {
               rightResult = DialogResult.Yes;
           }
           else if (File.Exists(folderPair.RightFolder.MarkerFilePath))
           {
               rightResult = DialogResult.Yes;
           }
           else
           {
               message = "CRSyncFiles has detected that you haven't synchronized Folder Pair : " + folderPair.FolderPairName + " with the following end point " + folderPair.RightFolder.Path + ". Would you like to continue?";
               rightResult = MessageBox.Show(message,
                               caption,
                               MessageBoxButtons.YesNo,
                               MessageBoxIcon.Question,
                               MessageBoxDefaultButton.Button2);
           }

           return (leftResult == DialogResult.Yes) && (rightResult == DialogResult.Yes);
       }

        
        //----------------------- CALL BACKS --------------------------------


        protected virtual void CallBackClosed( object sender, EventArgs args)
        {
            /************************************************************************************
             * If reset is invoked no need to remember current window's position and dimension.
             * Otherwise, the resetting of user settings ( default values ) will not happened.
             * The reason is that, the "RESET" does not loops through all the keys and values and 
             * set them to default. Instead, will look for the settings file and delete it and 
             * let the application settings manager generate all the default values for us.
             * However, the default values will not generate until the next application run/load.
             * So in this case, calling StoreWindowsPositionAndDimentsion() while the settings
             * file is gone/deleted will only regenerate the settings file with the last known 
             * values. 
             * ***********************************************************************************/

            if (!_resetOnGoing)
            {
                StoreWindowPositionAndDimension();
            }
        }

        protected virtual void CallBackShown(object sender , EventArgs args)
        {
            // Display welcome screen);
            if(!Settings.Default.CFG_DO_NOT_SHOW_WELCOME_SCREEN_1)
            {
                var dlgWelcomeScreen = new CrSyncUiWelcomeScreen1();
                dlgWelcomeScreen.ShowDialog(this);
            }

            OnShownExtension();
        }

        private void CallBackFolderPairTreeNodeHover(object sender, TreeNodeMouseHoverEventArgs e)
       {
           if (ApplicationGlobals.PairManager.HasFolderPairNamed(e.Node.Text))
           {
               var currentPair = ApplicationGlobals.PairManager.CurrentFolderPair;
               if (currentPair.Validate(ApplicationGlobals.PairManager) != CrSyncFileLocationResult.Valid)
               {
                   e.Node.ToolTipText = "One or Both Folders no longer exists on the Hard Drive";
               }
           }
       }

       private void CallBackFolderPairTreeSelectionBefore(object sender, TreeViewCancelEventArgs e)
       {
           if ((_currentPairNode != e.Node) && (_currentPairNode != null))
           {
               if (_currentPairNode.BackColor == _unfocusedFolderPairColor)
               {
                   _currentPairNode.BackColor = Color.Empty;
                   _currentPairNode.ForeColor = CRSyncColors.ListViewForeColor;
               }
           }

           _currentPairNode = e.Node;
       }

       private void CallBackFolderPairTreeSelection(object sender, TreeViewEventArgs e)
       {
            LoadFolderPairNamed(e.Node.Text.Trim());
            if (_doneLoadingFromLastKnownFolderPair)
            {
                ApplicationGlobals.SetLastRunFolderPair(e.Node.Text.Trim());
            }
            ApplicationGlobals.SetVerboseMessage(string.Format("Folder Pair : {0} is selected.", e.Node.Text.Trim()));
       }


       private void CallBackFolderPairLeave(object sender, EventArgs e)
       {
           if (FolderPairTree.SelectedNode != null)
           {
               _currentPairNode = FolderPairTree.SelectedNode;
               _currentPairNode.BackColor = _unfocusedFolderPairColor;
               _currentPairNode.ForeColor = CRSyncColors.ListViewForeColor2;
           }
       }


       public void CallBackFolderPairsContextMenuPopped(object sender, EventArgs e)
       {
           try
           {
               var overrideMethodInfo = GetType().GetMethod("OverrideCallBackFolderPairsContextMenuPopped");
               var overrideArgs = new Object[] {sender, e};
               overrideMethodInfo.Invoke(this, overrideArgs);
           }
           catch (NullReferenceException)
           {
               if (FolderPairTree.Nodes.Count >= 1)
               {
                   var selectedFolderPair = FolderPairTree.SelectedNode.Text;

                   var pairManager = ApplicationGlobals.PairManager;
                   FolderPairsContextMenu.MenuItems.Clear();
                   FolderPairsContextMenu.MenuItems.Add(MenuItemCreateNewFolderPair);
                   
                   if (selectedFolderPair != KAll_FOLDER_PAIRS)
                   {
                       MenuItemRenameFolderPair.Text = Resources.TEXT_RENAME + selectedFolderPair + "...";
                       MenuItemDeleteFolderPair.Text = Resources.TEXT_DELETE + selectedFolderPair;

                       FolderPairsContextMenu.MenuItems.Add(MenuItemRenameFolderPair);
                       FolderPairsContextMenu.MenuItems.Add(MenuItemDeleteFolderPair);
                   }
               }
               else
               {
                   FolderPairsContextMenu.MenuItems.Clear();
                   FolderPairsContextMenu.MenuItems.Add(MenuItemCreateNewFolderPair);
               }
           }
       }
        
       
       protected virtual  void CallBackFolderPairContextMenuMeasure(object sender, MeasureItemEventArgs args)
       {
           args.ItemHeight = 18;
           args.ItemWidth = 250;
       }

        

       private void PauseDuringOperationClicked(object sender, EventArgs e)
       {
           if (MenuItemDiagnosticPause.Checked)
           {
               ApplicationGlobals.CfgDefaultPauseTime = 0;
               MenuItemDiagnosticPause.Checked = false;
           }
           else
           {
               ApplicationGlobals.CfgDefaultPauseTime = 1000;
               MenuItemDiagnosticPause.Checked = true;
           }
       }


       
       protected void CallBackRun(object sender, EventArgs e)
       {
           FolderPairTree.Focus();
           FolderPairTree.Select();
           var eventSender = (Button)sender;
           if (eventSender.Text == Resources.TEXT_RUN_ALL)
           {
               var selectedFolderPairs = PanelAllFolderPairs.GetAllActiveFolderPairs();
               if (selectedFolderPairs.Count >= 1)
               {
                   // Loop through each Folder Pair and upate the last run date time stamp.
                   foreach (var pairItem in selectedFolderPairs)
                   {
                       pairItem.DateTimeLastSync = DateTime.Now;
                       ApplicationGlobals.PairManager.UpdateFolderPair(pairItem);
                       ApplicationGlobals.SyncToyManager.UpdateFolderPair(pairItem);
                   }

                   var syncController = new FileSynchronizerManager(selectedFolderPairs,
                                                                   true,
                                                                   Settings.Default,
                                                                   ConfigurationManager.AppSettings["SyncProvider"]);
                   var fileSynchronizer = syncController.GetSynchronizer();

                   DialogSyncToyResult = new CrSyncUiRun(fileSynchronizer);
                   DialogSyncToyResult.ShowDialog(this);
                   ApplicationGlobals.SetLastRunFolderPair("All Folder Pairs");
               }
               else
               {
                   MessageBox.Show(Resources.MESSAGE_NO_ACTIVE_PAIRS_TO_RUN, Resources.TEXT_SHORT_NAME, MessageBoxButtons.OK, MessageBoxIcon.Information);
               }
           }
           else
           {
               // Run a single Folder Pair
               var currentFolderPairItem = FolderPairTree.SelectedNode.Text;
               var index = FolderPairTree.SelectedNode.Index;
               if (ApplicationGlobals.PairManager.HasFolderPairNamed(currentFolderPairItem))
               {
                   var currentFolderPair = ApplicationGlobals.PairManager.CurrentFolderPair;

                   if (CheckMissingEndpointAndContinue(currentFolderPair))
                   {
                       currentFolderPair.CreateMarkerFiles();
                       currentFolderPair.DateTimeLastSync = DateTime.Now;
                       ApplicationGlobals.PairManager.UpdateFolderPair(currentFolderPair);
                       ApplicationGlobals.SyncToyManager.UpdateFolderPair(currentFolderPair);

                       var syncController = new FileSynchronizerManager(new List<FileSyncPairInfo> { currentFolderPair },
                                                                   true,
                                                                   Settings.Default,
                                                                   ConfigurationManager.AppSettings["SyncProvider"]);
                       var fileSynchronizer = syncController.GetSynchronizer();

                       DialogSyncToyResult = new CrSyncUiRun(fileSynchronizer);
                       DialogSyncToyResult.ShowDialog(this);
                       InitializeFolderPairTree();
                       FolderPairTree.SelectedNode = FolderPairTree.Nodes[index];
                       FolderPairTree.SelectedNode.BackColor = Color.FromArgb(240, 240, 240);
                       // Update SyncToy last run Folder Pair
                       ApplicationGlobals.SetLastRunFolderPair(currentFolderPair.FolderPairName);
                   }

               }
               else
               {
                   MessageBox.Show(Resources.TEXT_SELECTED_PAIR_DOES_NOT_EXISTS);
               }
           }
       }

        


       private void CallBackPreview(object sender, EventArgs e)
       {
           var aButton = sender as Button;
           if (aButton != null)
           {

               FolderPairTree.Focus();
               FolderPairTree.Select();

               if (aButton.Text == Resources.TEXT_PREVIEW_ALL)
               {

                   var selectedFolderPairs = PanelAllFolderPairs.GetAllActiveFolderPairs();
                   if (selectedFolderPairs.Count >= 1)
                   {

                       var syncController = new FileSynchronizerManager(selectedFolderPairs,
                                                                   true,
                                                                   Settings.Default,
                                                                   ConfigurationManager.AppSettings["SyncProvider"]);
                       var fileSynchronizer = syncController.GetSynchronizer();

                       var runPreview = new CrSyncUiPreview(fileSynchronizer);
                       runPreview.ShowDialog();
                       ApplicationGlobals.SetLastRunFolderPair("All Folder Pairs");
                   }
                   else
                   {
                       MessageBox.Show(Resources.MESSAGE_NO_ACTIVE_PAIRS_TO_RUN, Resources.TEXT_SHORT_NAME,
                                       MessageBoxButtons.OK, MessageBoxIcon.Information);
                   }
               }
               else
               {
                   var selectedFolderPair = FolderPairTree.SelectedNode.Text;
                   if (ApplicationGlobals.PairManager.HasFolderPairNamed(selectedFolderPair))
                   {
                       var currentFolderPair = ApplicationGlobals.PairManager.CurrentFolderPair;


                       if (CheckMissingEndpointAndContinue(currentFolderPair))
                       {
                           currentFolderPair.CreateMarkerFiles();

                           var syncController = new FileSynchronizerManager(new List<FileSyncPairInfo> { currentFolderPair },
                                                                   true,
                                                                   Settings.Default,
                                                                   ConfigurationManager.AppSettings["SyncProvider"]);
                           var fileSynchronizer = syncController.GetSynchronizer();
                           var runPreview = new CrSyncUiPreview(fileSynchronizer);
                           runPreview.ShowDialog();
                           //LabelLastRun.Text = ApplicationGlobals.PairManager.CurrentFolderPair.LastRunDisplayString;
                           ApplicationGlobals.SetLastRunFolderPair(currentFolderPair.FolderPairName);

                           // Update SyncToy and CRSyncFiles "Last Run" date/time.
                           ApplicationGlobals.PairManager.UpdateFolderPair(currentFolderPair);
                           ApplicationGlobals.SyncToyManager.UpdateFolderPair(currentFolderPair);
                           LoadFolderPairNamed(currentFolderPair.FolderPairName);
                       }

                   }
                   else
                   {
                       MessageBox.Show(Resources.MESSAGE_NO_FOLDER_PAIR_ASSOCIATED_WITH_THAT_NAME,
                                       Resources.TEXT_TITLE_NAME, MessageBoxButtons.OK, MessageBoxIcon.Information);
                   }
               }
           }
       }


        
       private void CallBackCreateNewFolderPair(object sender, EventArgs e)
       {
           DialogFolderPairWizard = new CrSyncUiFolderPairWizard();
           var folderPairWizardResult = DialogFolderPairWizard.ShowDialog(this);
           switch (folderPairWizardResult)
           {
               case DialogResult.OK:
                   {
                       FolderPairTree.Focus();
                       FolderPairTree.Select();
                       Cursor = Cursors.WaitCursor;
                       _preloaderCreateNewFolder = new CrSyncUiPreLoaderDialog
                                                       {
                                                           StatusMessage = Resources.MESSAGE_CREATING_FOLDER_PAIR,
                                                           Timeout = 30,
                                                           TimeBeforeAutoCancel = 15,
                                                           TimeoutMessage = "Processing, please wait..."
                                                       };
                       _preloaderCreateNewFolder.BackgroundThread.DoWork += CallBackCreateNewFolderPairWorker;
                       _preloaderCreateNewFolder.BackgroundThread.RunWorkerCompleted += CallBackCreateNewFolderPairWorkerCompleted;
                       _preloaderCreateNewFolder.ErrorOnClose += CallBackCreateNewFolderPairTimeoutError;
                       _preloaderCreateNewFolder.ShowDialog(this);
                   }
                break;
               default:
                   FolderPairTree.Select();
                   break;
           }

       }

        protected virtual void CallBackCreateNewFolderPairTimeoutError(object sender, EventArgs args)
        {
            Cursor = Cursors.Default;
            MessageBox.Show(this,
                Resources.MESSAGE_SERVER_TIMEOUT,
                Resources.TEXT_SHORT_NAME,
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            CrSyncFilesUtility.WriteLog(Resources.MESSAGE_SERVER_TIMEOUT_2, ApplicationGlobals.CrSyncCriticalLogFilePath);
            ApplicationGlobals.RegistryManager.SetValueForKey("True", "CFG_SHOW_CRITICAL_LOG");
        }

        protected virtual void CallBackCancelCreateNewFolderPair(object sender, EventArgs args)
        {
            try
            {
                _preloaderCreateNewFolder.CancelAndClose();
                //_preloaderCreateNewFolder.ClosePreloader();
                Cursor = Cursors.Default;
            }
            catch(Exception exception)
            {
                var exceptionMessage = "[ERROR]--------------------\r\n";
                exceptionMessage += "MESSAGE : " + exception.Message +"\r\n\r\n";
                exceptionMessage += string.Format("STACK : \r\n\r\n {0}", exception);
                ApplicationGlobals.SetVerboseMessage(exceptionMessage);
            }
        }

        /// <summary>
        /// Handles the process of creating folder pairs.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected virtual void CallBackCreateNewFolderPairWorker(object sender, DoWorkEventArgs args)
        {
            try
            {
                var overrideMethodInfo = GetType().GetMethod("OverrideCallBackCreateNewFolderPairWorker");
                var overrideArgs = new object[] {sender, args};
                overrideMethodInfo.Invoke(this, overrideArgs);
            }
            catch (NullReferenceException)
            {
                var backgroundWorker = sender as BackgroundWorker;
                var newFolderPair = DialogFolderPairWizard.FolderPair;

                // Store the new Folder Pair we created to SyncToy's data store.
                ApplicationGlobals.PairManager.AddFolderPair(newFolderPair);
                if (ApplicationGlobals.SyncToyManager.AddFolderPair(newFolderPair))
                {
                    newFolderPair.ExtendedInfo.AddObjectForKey(true, KHAS_MIRROR);
                    ApplicationGlobals.PairManager.UpdateFolderPair(newFolderPair);
                }

                _newFolderPair = newFolderPair;

                if (backgroundWorker != null) backgroundWorker.ReportProgress(0, true);
                args.Result = true; // Inform the background worker object that the process is a sucess.
            }
        }

        protected virtual void CallBackCreateNewFolderPairWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            
            Cursor = Cursors.Default;
            _preloaderCreateNewFolder.ClosePreloader();

            // Check if the process resulted in success or failure.
            if((bool)args.Result)
            {
                InitializeFolderPairTree();
                LoadFolderPairNamed(_newFolderPair.FolderPairName);

                // Select newly created Folder Pair.
                FolderPairTree.Select();
                foreach (var node in FolderPairTree.Nodes.Cast<TreeNode>().Where(node => node.Text == _newFolderPair.FolderPairName))
                {
                    FolderPairTree.SelectedNode = node;
                }

                if (FolderPairTree.Nodes.Count >= 2)
                {
                    ButtonDeleteFolderPair.Enabled = true;
                    ButtonRenameFolderPair.Enabled = true;
                }

                var verboseMessage = string.Format("Create a new Folder Pair :  {0}",
                                                    _newFolderPair.FolderPairName);
                ApplicationGlobals.SetVerboseMessage(verboseMessage);
                verboseMessage = string.Format("[LEFT DIRECTORY] {0}", _newFolderPair.LeftFolder.Path);
                ApplicationGlobals.SetVerboseMessage(verboseMessage);
                verboseMessage = string.Format("[RIGHT DIRECTORY] {0}", _newFolderPair.RightFolder.Path);
                ApplicationGlobals.SetVerboseMessage(verboseMessage);
            }
            
        }

       private void CallBackDeleteFolderPair(object sender, EventArgs e)
       {
           try
           {
               var overrideMethodInfo = GetType().GetMethod("OverrideDeleteFolderPair");
               overrideMethodInfo.Invoke(this, null);
           }
           catch (NullReferenceException)
           {
               DeleteFolderPair();
           }
       }

        public void DeleteFolderPair()
        {
            var currentFolderPairName = FolderPairTree.SelectedNode.Text;
            var deleteResult =
                MessageBox.Show(
                    string.Format(Resources.MESSAGE_DELETE_FOLDER_PAIR, currentFolderPairName),
                    Resources.TEXT_TITLE_NAME,
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question);


            switch (deleteResult)
            {
                case DialogResult.Yes:
                    if (ApplicationGlobals.PairManager.HasFolderPairNamed(currentFolderPairName))
                    {
                        var currentFolderPair = ApplicationGlobals.PairManager.CurrentFolderPair;

                        // Pass the hashtable that contains the current FileSyncPairInfo object and the the "state", if pair has been scheduled for reference.
                        var arguments = new Hashtable
                                            {
                                                {KCURRENT_FOLDER_PAIR, currentFolderPair},
                                            };
                        _preLoaderDeleteFolderPair = new CrSyncUiPreLoaderDialog
                        {
                            StatusMessage = "Deleting the Folder Pair...",
                            Timeout = 20,
                            TimeoutMessage = "Please try again in 5 minutes.",
                            TimeBeforeForceCancel = 5
                        };
                        _preLoaderDeleteFolderPair.BackgroundThread.DoWork += CallBackDeleteFolderPairWorker;
                        _preLoaderDeleteFolderPair.BackgroundThread.ProgressChanged += CallBackDeleteFolderPairProgressChanged;
                        _preLoaderDeleteFolderPair.BackgroundThread.RunWorkerCompleted += CallBackDeleteFolderPairWorkerCompleted;
                        _preLoaderDeleteFolderPair.BackgroundThreadArguments = arguments;
                        _preLoaderDeleteFolderPair.ShowDialog(this);



                    }
                    else
                    {
                        MessageBox.Show(string.Format("Unable to delete Folder Pair :  {0}", currentFolderPairName),
                                        Resources.TEXT_SHORT_NAME,
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                    }
                    InitializeFolderPairTree();
                    InitializeDefaultActions();

                    ApplicationGlobals.SetVerboseMessage(string.Format("Folder Pair :  {0} was deleted.", currentFolderPairName));

                    break;

                default:
                    FolderPairTree.Select();
                    break;
            }
        }

       public virtual void CallBackDeleteFolderPairWorker(object sender, DoWorkEventArgs args)
       {
           try
           {
               var overrideMethodInfo = GetType().GetMethod("OverrideCallBackDeleteFolderPairWorker");
               var overrideArgs = new object[] {sender, args};
               overrideMethodInfo.Invoke(this, overrideArgs);
           }
           catch (NullReferenceException)
           {
               var arguments = (Hashtable)args.Argument;
               var currentFolderPair = (FileSyncPairInfo)arguments[KCURRENT_FOLDER_PAIR];

               if (ApplicationGlobals.SyncToyManager.RemoveFolderPair(currentFolderPair))
               {
                   ApplicationGlobals.SetVerboseMessage("Folder Pair :  " + currentFolderPair.FolderPairName + " successfully removed from SyncToy's data store file.");
               }
               else
               {
                   ApplicationGlobals.SetVerboseMessage("Folder Pair :  " + currentFolderPair.FolderPairName + " could not be removed from SyncToy's data store file. Either SyncToy's store is not present, SyncToy's integration is disabled or there was a file permission error.");
               }

               if (ApplicationGlobals.PairManager.RemoveFolderPair(currentFolderPair))
               {
                   ApplicationGlobals.SetVerboseMessage("Folder Pair :  " + currentFolderPair.FolderPairName + " successfully removed from CRSyncFiles data store.");
               }
               else
               {
                   ApplicationGlobals.SetVerboseMessage("Folder Pair :  " + currentFolderPair.FolderPairName + " could not be removed from CRSyncFiles data store.");
               }
           }
       }

        
        protected virtual void CallBackDeleteFolderPairProgressChanged(object sender, ProgressChangedEventArgs args)
        {
            var message = (string) args.UserState;
            _preLoaderDeleteFolderPair.StatusMessage = message;
        }

        protected virtual void CallBackDeleteFolderPairWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            _preLoaderDeleteFolderPair.ClosePreloader();
        }


       private void CallBackRenameFolderPair(object sender, EventArgs e)
       {
           var currentFolderName = FolderPairTree.SelectedNode.Text;
           var dialogRename = new CrSyncUiRename(currentFolderName);
           switch (dialogRename.ShowDialog(this))
           {
               case DialogResult.OK:
                   {
                       var newName = dialogRename.FolderPairName.Trim();
                       if (currentFolderName != newName)
                       {
                           if (ApplicationGlobals.PairManager.RenameFolderPair(currentFolderName, newName))
                           {
                               ApplicationGlobals.SyncToyManager.RenameFolderPair(currentFolderName, newName);
                               InitializeFolderPairTree();
                               InitializeDefaultActions();
                               LoadFolderPairNamed(newName);
                               
                               foreach (var treeNode in
                                   FolderPairTree.Nodes.Cast<TreeNode>().Where(treeNode => treeNode.Text == newName))
                               {
                                   FolderPairTree.SelectedNode = treeNode;
                                   FolderPairTree.Select();
                                   break;
                               }
                           }
                           else
                           {
                               throw new ApplicationException(string.Format("Failed to rename Folder Pair :  {0} to {1}", currentFolderName, newName));
                           }
                       }
                   }
                   break;
               default:
                   FolderPairTree.Select();
                   break;
           }
       }

       protected void CallBackExit(object sender, EventArgs e)
       {
           ApplicationGlobals.SetVerboseMessage(string.Format("Exiting CRSyncFiles {0}",DateTime.Now));
           StoreWindowPositionAndDimension();
           Application.Exit();
       }

       private void CallBackViewLog(object sender, EventArgs e)
       {
           Cursor = Cursors.WaitCursor;
           DialogSyncToyLogs = new CrSyncUiLogViewer(ApplicationGlobals.CrSyncLogFilePath,"CRSyncFiles Execution Log");
           DialogSyncToyLogs.ShowDialog(this);
           Cursor = Cursors.Arrow;
       }

        private void CallBackForums(object sender, EventArgs e)
       {
           try
           {
               Process.Start(new ProcessStartInfo(Settings.Default.CFG_URL_FORUMS));
           }
           catch(Exception forumUrl)
           {
               ApplicationGlobals.SetVerboseMessage(forumUrl.Message);
               MessageBox.Show(string.Format("Could not open: {0}.", Settings.Default.CFG_URL_FORUMS));
           }
       }

       private void CallBackAbout(object sender, EventArgs e)
       {
           var dialogAbout = new CrSyncUiAbout();
           dialogAbout.ShowDialog();
       }

       private void MenutItemDebugClick(object sender, EventArgs e)
       {
           if(Settings.Default.CFG_ENABLE_DEBUG)
           {
               Settings.Default.CFG_ENABLE_DEBUG = false;
               Settings.Default.Save();
           }
           else
           {
               Settings.Default.CFG_ENABLE_DEBUG = true;
               Settings.Default.Save();
           }
       }

       private void CallBackToolsItemClicked(object sender, EventArgs e)
       {
           
       }

       private void CallBackShowVerboseWindow(object sender, EventArgs e)
       {
           if(ApplicationGlobals.Verbose)
           {
               ApplicationGlobals.Verbose = false;
               MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
               if(Program.VerboseWindow != null)
               {
                   Program.VerboseWindow.Close();
               }
           }
           else
           {
               ApplicationGlobals.Verbose = true;
               MenuItemDiagnosticsMode.Text = Resources.TEXT_OPEN_VERBOSE_WINDOW;
               MenuItemDiagnosticsMode.Enabled = false;

               Program.VerboseWindow = new CrSyncUiVerboseOutput();
               Program.VerboseWindow.Show();

               //Program.SpawnDiagnosticWindow();

               ApplicationGlobals.SetVerboseMessage(string.Format("Staring CRSyncFiles with Verbose Output enabled {0}",
                                                               DateTime.Now));
           }
       }

       private void CallBackShowAdvancedOptions(object sender, EventArgs e)
       {
           if(MenuItemAdvancedOptions.Checked)
           {
               MenuItemAdvancedOptions.Checked = false;
               Settings.Default.CFG_SHOW_ADVANCED_OPTIONS = false;
           }
           else
           {
               MenuItemAdvancedOptions.Checked = true;
               Settings.Default.CFG_SHOW_ADVANCED_OPTIONS = true;
           }

           // Update advanced options menu.
           MenuItemResetRegistryKey.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemDiagnosticsMode.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemDiagnosticPause.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemFolderPairExport.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemFolderPairImport.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           MenuItemWriteToEvent.Visible = Settings.Default.CFG_SHOW_ADVANCED_OPTIONS;
           Settings.Default.Save();

           OnShowAdvancedOptionsExtension();
       }

       private void CallBackShowVerboseModeMenuItem(object sender, KeyEventArgs e)
       {

           //if ((e.Control) && (e.Shift) && (e.KeyCode == Keys.V))
           //{
           //    ApplicationGlobals.WriteVerboseMessageToWindow("Invoking Verbose mode menu item.");
           //    if (MenuItemDiagnosticsMode.Visible)
           //    {
           //        MenuItemDiagnosticsMode.Visible = false;
           //    }
           //    else
           //    {
           //        MenuItemDiagnosticsMode.Visible = true;
           //    }
           //}

           if ((e.Control) && (e.Shift) && (e.KeyCode == Keys.E))
           {
               var dlg = new CrSyncUiExceptionDialog();
               dlg.ShowDialog(this);
           }
       }

       private void CallBackCrSyncFilesHelp(object sender, EventArgs e)
       {
           LaunchOnlineHelpFile();
       }


       protected virtual void CallBackHelp(object sender, LinkLabelLinkClickedEventArgs args)
       {
           LaunchOnlineHelpFile();
       }

       private void CallBackViewCriticalLog(object sender, EventArgs e)
       {
           ApplicationGlobals.RegistryManager.SetValueForKey("False", "CFG_SHOW_CRITICAL_LOG");
           InitializeCriticalErrorLink();
           ShowCriticalLogViewer();
       }

       private void CallBackCriticalErrorLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
       {
           ApplicationGlobals.RegistryManager.SetValueForKey("False", "CFG_SHOW_CRITICAL_LOG");
           InitializeCriticalErrorLink();
           ShowCriticalLogViewer();
       }

        private void CallBackRestoreDefaultSettings(object sender, EventArgs e)
        {
            _resetOnGoing = true;

            try
            {
                var result = MessageBox.Show(
                    Resources.MESSAGE_RESET_REGISTRY_KEYS,
                    Resources.TEXT_SHORT_NAME,
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question);

                if(result == DialogResult.Yes)
                {
                   
                    var regKey = Registry.CurrentUser.CreateSubKey("Software");
                    if (regKey != null)
                    {
                        regKey.DeleteSubKeyTree(Application.CompanyName);
                        var appDataDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + Application.CompanyName + "\\";
                        var subDirectories = Directory.GetDirectories(appDataDirectory);
                        
                        // Delete ConnectionRoad sub Folders.
                        foreach (var subDirectory in subDirectories)
                        {
                            try
                            {
                                var files = Directory.GetFiles(subDirectory);
                                foreach (var file in files)
                                {
                                    File.Delete(file);
                                }

                                File.Delete(appDataDirectory+"CRSyncFiles\\CrSyncFilesSettings.xml");

                                Directory.Delete(subDirectory, true);

                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message + "\r\n\r\n" + ex.StackTrace);
                            }
                        }

                        // Delete all of Synctoy's Folder Pairs.
                        ApplicationGlobals.SyncToyManager.Clear();

                    }
                    Close();
                }
            }
            catch (Exception exception)
            {
                var exceptionMessage = string.Format("[ERROR]--------------------------------------\r\n\r\n");
                exceptionMessage += string.Format("MESSAGE: {0}\r\n\r\n", exception.Message);
                exceptionMessage += string.Format("STACK:\r\n\r\n\r\n{0}", exception);
                exceptionMessage += "-------------------------------------------------------------------";
                ApplicationGlobals.SetVerboseMessage(exception.Message);
                CrSyncFilesUtility.WriteLog(exceptionMessage, Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)+"CRSyncFiles.Log");
                Close();
            }
        }

        private void CallBackExportXmlFile(object sender, EventArgs e)
        {
            ApplicationGlobals.SetVerboseMessage("Exporting the CRSyncFiles database...");
            var dlg = new SaveFileDialog
            {
                AddExtension = true,
                DefaultExt = ".xml",
                FileName = "CRSyncFiles",
                Filter = "XML files (*.xml)|*.xml",
                OverwritePrompt = true,
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                Title = "Export file to:"
            };

            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                var fileName = dlg.FileName;
                _preLoaderExport = new CrSyncUiPreLoaderDialog
                                       {
                                           BackgroundThreadArguments = fileName,
                                           StatusMessage = "Exporting Folder Pairs..."
                                       };
                _preLoaderExport.BackgroundThread.DoWork += CallBackExportXmlFileWorker;
                _preLoaderExport.BackgroundThread.RunWorkerCompleted += CallBackExportXmlFileWorkerCompleted;
                _preLoaderExport.ShowDialog(this);

            }
        }

        protected virtual void CallBackExportXmlFileWorker(object sender, DoWorkEventArgs args)
        {
            try
            {
                // Open the contents of the current XML file.
                var contents = File.ReadAllBytes(ApplicationGlobals.CrSyncStoreFilePath);
                var fileName = (string) args.Argument;
                using (var fileStream = File.Open(fileName,FileMode.Create))
                {
                    foreach (var content in contents)
                    {
                        fileStream.WriteByte(content);
                    }
                }

                ApplicationGlobals.SetVerboseMessage(string.Format("CRSyncFiles Folder Pairs were exported to :  {0}", fileName));

                args.Result = new Hashtable {{KRESULT,true},{KERROR,null}};
            }
            catch (Exception exception)
            {
                args.Result = new Hashtable {{KRESULT, false}, {KERROR, exception}};
            }
        }

        protected virtual void CallBackExportXmlFileWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            var result = (Hashtable) args.Result;
            
            if((bool)result[KRESULT])
            {
                _preLoaderExport.Close();
            }
            else
            {
                var exception = (Exception) result[KERROR];
                var errorMessage = string.Format("[ERROR]------------------------------------------\r\n\r\n");
                errorMessage += string.Format("MESSAGE : {0}\r\n\r\n", exception.Message);
                errorMessage += string.Format("EXCEPTION : {0}\r\n\r\n", exception);
                errorMessage += string.Format("STACK : \r\n\r\n{0}\r\n\r\n", exception.StackTrace);
                ApplicationGlobals.SetVerboseMessage(errorMessage);
                CrSyncFilesUtility.WriteLog(errorMessage, ApplicationGlobals.CrSyncCriticalLogFilePath);
                MessageBox.Show(this,
                                exception.Message,
                                Resources.TEXT_SHORT_NAME,
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Exclamation);
                _preLoaderExport.Close();
            }
            
        }

        private void CallBackImportXmlFile(object sender, EventArgs e)
        {
                 var shouldImport = MessageBox.Show(this,
                    Resources.MESSAGE_IMPORT_REMINDER,
                    Resources.TEXT_SHORT_NAME,
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question,
                    MessageBoxDefaultButton.Button1);

                 if (shouldImport == DialogResult.Yes)
                 {
                     ApplicationGlobals.SetVerboseMessage("Importing the CRSyncFiles database...");
                     var dlg = new OpenFileDialog
                                   {
                                       AddExtension = true,
                                       CheckFileExists = true,
                                       DefaultExt = "*.xml",
                                       Filter = "XML File (*.xml)|*.xml",
                                       InitialDirectory =   Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                                       Multiselect = false,
                                       Title = "Import file"
                                   };

                     if (dlg.ShowDialog(this) == DialogResult.OK)
                     {
                         Cursor = Cursors.WaitCursor;
                         _preLoaderImport = new CrSyncUiPreLoaderDialog
                                                {
                                                    StatusMessage = "Importing Folder Pairs...",
                                                    BackgroundThread = {WorkerReportsProgress = true},
                                                    BackgroundThreadArguments = dlg.FileName
                                                };
                         _preLoaderImport.BackgroundThread.DoWork += CallBackImportXmlFileWoker;
                         _preLoaderImport.BackgroundThread.RunWorkerCompleted += CallBackImportXmlFileCompleted;
                         _preLoaderImport.ShowDialog();
                     }
                 }

        }

        protected virtual void CallBackImportXmlFileWoker(object sender , DoWorkEventArgs args)
        {
            try
            {
                try
                {
                    var overrideMethodInfo = GetType().GetMethod("OverrideImportXmlFile");
                    var overrideArgs = new object[] {args};
                    overrideMethodInfo.Invoke(this, overrideArgs);
                }
                catch (MissingMethodException)
                {
                    ImportXmlFile(args);
                }
            }
            catch (InvalidOperationException invalidOperation)
            {
                args.Result = new Hashtable { { KRESULT, false }, { KERROR, invalidOperation } };
            }
            catch (Exception exception)
            {
                args.Result = new Hashtable { { KRESULT, false }, { KERROR, exception } };
                
            }
        }


        public void ImportXmlFile(DoWorkEventArgs args)
        {
            var fileName = (string)args.Argument;
            var importManager = new FileSyncPairManager(fileName);
            var importedDocumentInfo = importManager.GetFileSyncPairDocumentInfo();


            foreach (var fileSyncPairInfo in importedDocumentInfo.FolderPairs)
            {
                // Repair marker files
                if (fileSyncPairInfo.LeftFolder.Validate(fileSyncPairInfo, ApplicationGlobals.PairManager) == CrSyncFileLocationResult.Valid)
                {
                    fileSyncPairInfo.LeftFolder.CreateMarker();
                }

                if (fileSyncPairInfo.RightFolder.Validate(fileSyncPairInfo, ApplicationGlobals.PairManager) == CrSyncFileLocationResult.Valid)
                {
                    fileSyncPairInfo.RightFolder.CreateMarker();
                }


            }

            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["AppDataPostFix"]))
            {
                // Overwrite SyncToy's database if necessary
                if (Settings.Default.CFG_RUN_STATE == (int)CrSyncFilesRunState.Slave)
                {
                    ApplicationGlobals.SyncToyManager.Clear();
                    var folderPairs = importedDocumentInfo.FolderPairs;
                    foreach (var folderPair in folderPairs)
                    {
                        ApplicationGlobals.SyncToyManager.AddFolderPair(folderPair);
                    }
                }
            }
            else
            {
                /****************************************************************
                 * ConfigurationManager.AppSettings["AppDataPostFix"] is not null.
                 * Assume as a master app do nothing for SyncToy.
                 * **************************************************************/
            }


            // IMPORTANT: Always save / update CRSyncFiles' folder pair info after updating SyncToy folder pairs to ensure both properties are in-sync.
            ApplicationGlobals.PairManager.SetFileSyncPairDocumentInfo(importedDocumentInfo);

            ApplicationGlobals.SetVerboseMessage(string.Format("Successfully imported {0} Folder Pair(s)...", importedDocumentInfo.FolderPairs.Count));

            var result = new Hashtable { { KRESULT, true }, { KERROR, null } };
            args.Result = result;
        }

        protected virtual void CallBackImportXmlFileCompleted(object sender , RunWorkerCompletedEventArgs args)
        {
            var result = (Hashtable)args.Result;
            Cursor = Cursors.Default;
            if ((bool)result[KRESULT])
            {
                InitializeFolderPairTree();
                InitializeDefaultActions();
                _preLoaderImport.Close();
            }
            else
            {
                var errorObject = result[KERROR];
                if (errorObject.GetType() == typeof(InvalidOperationException))
                {
                    var invalidOperation = (InvalidOperationException)errorObject;

                    ApplicationGlobals.SetVerboseMessage(invalidOperation.Message);
                    MessageBox.Show(this,
                                    Resources.MESSAGE_READING_XML_FILE,
                                    Resources.TEXT_SHORT_NAME,
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                    _preLoaderImport.Close();
                }
                else
                {
                    var exception = (Exception)errorObject;

                    var errorMessage = string.Format("[ERROR ]--------------------\r\n\r\n");
                    errorMessage += string.Format("MESSAGE : {0}\r\n\r\n", exception.Message);
                    errorMessage += string.Format("EXCEPTION : {0}\r\n\r\n", exception.GetType());
                    errorMessage += string.Format("STACK : \r\n\r\n{0}\r\n\r\n", exception.StackTrace);
                    ApplicationGlobals.SetVerboseMessage(errorMessage);
                    CrSyncFilesUtility.WriteLog(errorMessage, ApplicationGlobals.CrSyncCriticalLogFilePath);

                    MessageBox.Show(this,
                                    exception.Message,
                                    Resources.TEXT_SHORT_NAME,
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                    _preLoaderImport.Close();
                }
            }
        }

        

        private void CallBackWriteToEvent(object sender, EventArgs e)
        {
            if(MenuItemWriteToEvent.Checked)
            {
                MenuItemWriteToEvent.Checked = false;
            }
            else
            {
                MenuItemWriteToEvent.Checked = true;
            }

            Settings.Default.CFG_WRITE_TO_EVENT_VIEWER = MenuItemWriteToEvent.Checked;
            Settings.Default.Save();
        }

        private void PanelAllFolderPairs_Load(object sender, EventArgs e)
        {

        }

        private void CallbackHomePage(object sender, EventArgs e)
        {

            try
            {
                Process.Start(new ProcessStartInfo(Settings.Default.CFG_URL_HOME_PAGE));
            }
            catch (Exception forumUrl)
            {
                ApplicationGlobals.SetVerboseMessage(forumUrl.Message);
                MessageBox.Show(string.Format("Could not open: {0}.", Settings.Default.CFG_URL_HOME_PAGE));
            }


        }

        private void CallbackProductsPage(object sender, EventArgs e)
        {

            try
            {
                Process.Start(new ProcessStartInfo(Settings.Default.CFG_URL_PRODUCTS_PAGE));
            }
            catch (Exception forumUrl)
            {
                ApplicationGlobals.SetVerboseMessage(forumUrl.Message);
                MessageBox.Show(string.Format("Could not open: {0}.", Settings.Default.CFG_URL_PRODUCTS_PAGE));
            }
        }

        
   }
}
